//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_JAVA_ARRAY_H
#define _UXS_JAVA_ARRAY_H

#pragma once

#include "JavaEnvironment.h"

namespace UX_STL
{
namespace  Java
{
	
	//
	// Array
	//

	template <typename T>
	struct JavaArray {};

#	define JNI_ARRAY_TYPE( _type, _type2 ) \
		template <> \
		struct JavaArray <_type> \
		{ \
		/* types */ \
		public: \
			typedef _type			value_t; \
			typedef _type##Array	jarray_t; \
		\
		/* variables */ \
		private: \
			Ptr< _type >	_data; \
			jarray_t		_arr; \
			usize			_count; \
			bool			_readOnly; \
			bool const		_fromNative; 	/* true if created in native code */ \
		\
		/* methods */ \
		public: \
			JavaArray () : \
				_data(null), _arr(null), _count(0), _readOnly(false), _fromNative(false) \
			{} \
			\
			\
			explicit \
			JavaArray (jarray_t arr, bool readOnly = false) : \
				_arr(arr), _data(null), _count(0), _readOnly(readOnly), _fromNative(false) \
			{ \
				JavaEnv je; \
				\
				_data  = je->Get##_type2##ArrayElements( arr, 0 ); \
				_count = je->GetArrayLength( arr ); \
			} \
			\
			\
			explicit \
			JavaArray (const uni_array<_type> &nativeArray) : \
				_arr(null), _data(null), _count(0), _readOnly(false), _fromNative(true) \
			{ \
				JavaEnv je; \
				\
				_arr   = je->New##_type2##Array( nativeArray.Count() ); \
				_data  = je->Get##_type2##ArrayElements( _arr, null ); \
				_count = je->GetArrayLength( _arr ); \
				\
				FOR( i, nativeArray ) { \
					_data[i] = nativeArray[i]; \
				} \
			} \
			\
			\
			explicit \
			JavaArray (const uni_array<const _type> &nativeArray) : \
				_arr(null), _data(null), _count(0), _readOnly(false), _fromNative(true) \
			{ \
				JavaEnv je; \
				\
				_arr   = je->New##_type2##Array( nativeArray.Count() ); \
				_data  = je->Get##_type2##ArrayElements( _arr, null ); \
				_count = je->GetArrayLength( _arr ); \
				\
				FOR( i, nativeArray ) { \
					_data[i] = nativeArray[i]; \
				} \
			} \
			\
			\
			~JavaArray () \
			{ \
				JavaEnv je; \
				\
				if ( _fromNative ) \
				{ \
					if ( _arr != null ) \
						je->DeleteLocalRef( _arr ); \
				} \
				else \
				if ( _data.IsNotNull() and _arr != null ) \
					je->Release##_type2##ArrayElements( _arr, _data.ptr(), _readOnly ? 0 : JNI_ABORT ); \
			} \
			\
			\
			const _type *	ptr ()				const	{ return _data; } \
			_type *			ptr ()						{ ASSERT( not _readOnly );  return _data; } \
			usize			Count ()			const	{ return _count; } \
			usize			Size ()				const	{ return _count * sizeof(value_t); } \
			bool			IsReadOnly ()		const	{ return _readOnly; } \
			\
			jarray_t		jarray ()			const	{ ASSUME( _arr != null ); return _arr; } \
			\
			_type const &	operator [] (int i)	const	{ return ptr()[i]; } \
			_type &			operator [] (int i)			{ return ptr()[i]; } \
			\
			operator uni_array< const _type > () const	{ return uni_array< const _type >( ptr(), Count() ); } \
			operator uni_array< _type >		  ()		{ return uni_array< _type >( ptr(), Count() ); } \
			\
			\
			template <typename B> \
			const uni_array< const B >	To () const \
			{ \
				STATIC_ASSERTE( sizeof(B) == sizeof(value_t) ); \
				return uni_array< const B >( (B *)ptr(), Count() ); \
			} \
			\
			\
			template <typename B> \
			const uni_array< const B >	Cast () const \
			{ \
				ASSERT( Size() % sizeof(B) == 0 ); \
				return uni_array< const B >( (B *) ptr(), Size() / sizeof(B) ); \
			} \
		}

	//JNI_ARRAY_TYPE( jboolean,	Boolean	);
	JNI_ARRAY_TYPE( jbyte,		Byte	);
	JNI_ARRAY_TYPE( jchar,		Char	);
	JNI_ARRAY_TYPE( jshort,		Short	);
	JNI_ARRAY_TYPE( jint,		Int		);
	JNI_ARRAY_TYPE( jlong,		Long	);
	JNI_ARRAY_TYPE( jfloat,		Float	);
	JNI_ARRAY_TYPE( jdouble,	Double	);

#	undef JNI_ARRAY_TYPE


}	// Java
}	// UX_STL

#endif	// _UXS_JAVA_ARRAY_H